# @FileName  : udp.py
# @Time      : 2022/8/29
# @Author    : LuZhaoHui
# @Software  : PyCharm

"""
UDP 通讯广播消息
"""

import socket
import threading
import time
import psutil

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *


class UDPBroadcastSend:

    def __init__(self, port):
        super().__init__()
        self.port = port
        self.broadcastNetWork, self.localIp = getBroadcastAddress('192.168.1.1')

    def sendBroadcastInfo(self, info):
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        try:
            self.socket.sendto(info.encode("utf-8"), (self.broadcastNetWork, self.port))
        except Exception as e:
                print(e)
        # self.thread = threading.Thread(target=self.sendInfo, arg=(info,))
        # self.thread.setDaemon(True)
        # self.thread.start()


class UDPBroadcastRecv(QThread):
    update_item = pyqtSignal(list)

    def __init__(self, port, size=4096):
        super().__init__()
        self.port = port
        self.isRecv = False
        self.size = size
        self.socket = None
        self.startListen()

    def startListen(self):
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        # 绑定端口+地址
        self.socket.bind(('', self.port))
        self.isRecv = True
        # self.thread = threading.Thread(target=self.startListenMsg)
        # self.thread.setDaemon(True)
        # self.thread.start()

    def run(self):
        while True:
            try:
                # recv
                data, addr = self.socket.recvfrom(self.size)
                if data:
                    msg = data.decode('utf-8')
                    self.update_item.emit([addr[0], msg])
            except Exception as e:
                print(e)
            if not self.isRecv:
                self.socket.close()
                self.update_item.emit([])
                break


def get_broad_addr(ipstr, maskstr):
    ipstrArr = ipstr.split(".")
    # print(ipstr)
    iptokens = list(map(int, ipstrArr))
    maskstrArr = maskstr.split(".")
    masktokens = list(map(int, maskstrArr))
    broadlist = []
    for i in range(len(iptokens)):
        ip = iptokens[i]
        mask = masktokens[i]
        broad = ip & mask | (~mask & 255)
        broadlist.append(broad)
    return '.'.join(map(str, broadlist))


def get_netcard():
    netcard_info = []
    info = psutil.net_if_addrs()
    for k, v in info.items():
        # print('k == ', k, 'v == ', v)
        for item in v:
            ip_netmask = {}
            if item[0] == 2 and not item[1] == '127.0.0.1':
                ip_netmask['ip'] = item[1]
                ip_netmask['netmask'] = item[2]
                netcard_info.append(ip_netmask)
    return netcard_info


# 获取本机IP
def get_host_ip():
    ip = ''
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(('8.8.8.8', 80))
        ip = s.getsockname()[0]
    except Exception as e:
        code = e.args[0]
        if code == 51:
            print('获取IP失败=============没有网络=============')
    finally:
        s.close()
    return ip


# 获取广播地址
def getBroadcastAddress(server_ip):
    info = get_netcard()
    if server_ip == '':
        ip = get_host_ip()
    else:
        ip = server_ip
    broadcastAddress = '255.255.255.0'  # 默认值，没有太多用处
    if ip != '':
        for item in info:
            addr = get_broad_addr(item['ip'], item['netmask'])
            if addr == get_broad_addr(ip, broadcastAddress):
                broadcastAddress = addr
                ip = item['ip']
                break
    # print('broadcastIp == ', broadcastAddress)
    return broadcastAddress, ip
